#pragma once
#include "rtdev/tio/tio_intf.h"

//class
using rtdev::TioBoardItf;
using rtdev::TioSysIoItf;
using rtdev::TioUsrIoItf;
//enum&struct
using rtdev::RS485Mode;
using rtdev::RS485RTUConfig;
using rtdev::TioKeys;
using rtdev::TioLampColor;

typedef enum  //used by function id 0x700 0x710
{
    TIO_VERSION_R = 0x001,
    TIO_OUT_VOLTAGE_RW = 0x100,
    TIO_DI_CFG_RW = 0x101,
    TIO_DO_CFG_RW = 0x102,
    TIO_AI_CFG_RW = 0x103,
    TIO_RS485_2_MOD_RW = 0x104,
    TIO_RS485_1_MOD_RW = 0x105,
    TIO_RS485_2_COMM_RW = 0x106,
    TIO_RS485_1_COMM_RW = 0x107,
    TIO_SENSOR_TYPE_CFG_RW = 0x108,    //
    TIO_SENSOR_DATA_CYCLE_RW = 0x109,  //
    TIO_SENSOR_CHN_CFG_RW = 0x10A,
    TIO_GYRO_ENABLE_RW = 0x10B,  //no used
    TIO_VOUT_ENABLE_RW = 0x301,
    TIO_KEYS_STATUS_R = 0x201,      //repeated function in PDO 0x190
    TIO_DI_STATUS_R = 0x202,        //repeated function in PDO 0x190
    TIO_DO_STATUS_R = 0x203,        //repeated function in PDO 0x190
    TIO_AI1_STATUS_R = 0x204,       //repeated function in PDO 0x190
    TIO_AI2_STATUS_R = 0x205,       //repeated function in PDO 0x190
    TIO_RGB_STATUS_R = 0x206,       //repeated function in PDO 0x190
    TIO_HEARTBEAT_CYCLE_R = 0x207,  //
    TIO_OUT_CURRENT_R = 0x208,      //
    TIO_INPUT_VOLTAGE_R = 0x209,    //
    TIO_TEMPERATURE_R = 0x20A,      //
} TioParamCode;

typedef enum
{
    TIO_STATUS_R = 0x190,
    TIO_STATUS_W = 0x210,
    TIO_PARAM_CFG_R = 0x700,
    TIO_PARAM_CFG_W = 0x710,
    TIO_RS485_2_R = 0x720,
    TIO_RS485_2_W = 0x721,
    TIO_RS485_1_R = 0x730,
    TIO_RS485_1_W = 0x731,
    TIO_RS485_3_R = 0x740,    //
    TIO_GYRO_DATA_R = 0x750,  //
} TioFuncCode;

class TioV3Board;

class TioV3SysIoItf : public TioSysIoItf
{
public:
    TioV3SysIoItf() {}
    ~TioV3SysIoItf() = default;
    int set_tio_RGB(TioLampColor color) override;
    int get_tio_RGB() override;

    TioKeys get_tio_keys() override;
    TioLampColor cmd_RGB_ = TioLampColor::TIO_LAMP_AUTO;
    uint8_t fb_RGB_ = 0;
    TioKeys fb_keys_ = {0};
    struct RobCfg
    {
        uint32_t cfg_vout_enable = 0;   //0 for power off, 1 for power on
        uint32_t cfg_vout_voltage = 0;  // 0 for 24V, 1 for 12V
    };

    int16_t hw_version_ = 0;
    int16_t sw_version_ = 0;

    RobCfg cmd_cfg_ = {};
    RobCfg fb_cfg_ = {};
    TioV3Board* tiov3 = nullptr;

public:
    int query_Tio_version() override;

    uint32_t get_tio_version() override;

    //paramcode 0x0301
    // 0 for power off, 1 for power on
    int tio_set_vout_enable(uint32_t cfg) override;
    int tio_get_vout_enable() override;
    //paramcode 0x0100
    //  0 for 24V, 1 for 12V
    int tio_set_vout_voltage(uint32_t data) override;
    int tio_get_vout_voltage() override;

private:
    int32_t data_;
};

class TioV3UsrIoItf : public TioUsrIoItf
{
    //todo:
    //[] 实现rs485报文处理
    //[] 实现io读写和配置
public:
    static const int di_cnt__ = 2;
    static const int do_cnt__ = 2;
    static const int ai_cnt__ = 2;
    static const int ao_cnt__ = 0;

    TioV3UsrIoItf() : rs485_trans_buffer_(MAX_RS485_CHANNEL, boost::circular_buffer<char>(MAX_TRANS_MSG_LEN)) {}
    ~TioV3UsrIoItf() = default;
    size_t get_di_cnt() override { return di_cnt__; }
    size_t get_do_cnt() override { return do_cnt__; }
    size_t get_ai_cnt() override { return ai_cnt__; }
    size_t get_ao_cnt() override { return ao_cnt__; }
    struct IoStat
    {
        uint8_t di_buffer = 0;
        uint8_t do_buffer = 0;
        uint16_t ai[2] = {0};
        uint8_t is_overload = 0;
        uint32_t di_config = 0;
        uint32_t do_config = 0;
        uint32_t ai_config = 0;
    } stat_;

    struct IoConfig
    {
        // 0:0x00 DI2输入类型为NPN,DI1输入类型为NPN
        // 1:0x01 DI2输入类型为NPN,DI1输入类型为PNP
        // 2:0x10 DI2输入类型为PNP,DI1输入类型为NPN
        // 3:0x11 DI2输入类型为PNP,DI1输入类型为PNP
        //  写入0x0101参数
        uint32_t di_config = 0;
        // 低8位数据有效，低8位数据中，高4位为DO2配置，低四位为DO1配置，具体含义如下：
        // 0x0 DO输出为类型为NPN输出
        // 0x1 DO输出类型为PNP输出
        // 0x2 DO输出类型为推挽输出
        // 0xF RS485H接口使能，DO禁止
        // 写入0x0102参数
        uint32_t do_config = 0;
        // 0:模拟输入功能使能，RS485L禁止
        // 1:RS485L接口使能，模拟输入功能禁止
        // 写入0x0103参数
        uint32_t ai_config = 0;
        uint8_t set_do = 0;
    } cmd_;
    TioV3Board* tiov3 = nullptr;

    int set_di(std::vector<int8_t> input) override { return -1; }    //不支持此功能，预留仿真强制di的扩展性
    int set_ai(std::vector<double> input) override { return -1; }    //不支持此功能，预留仿真强制di的扩展性
    int set_ao(std::vector<double> input) override { return -1; }    //不支持此功能，预留仿真强制di的扩展性
    int get_ao(std::vector<double>& output) override { return -1; }  //不支持此功能，预留仿真强制di的扩展性
    int get_di(std::vector<int8_t>& output) override;
    int set_do(std::vector<int8_t> input) override;
    int get_do(std::vector<int8_t>& output) override;
    int get_ai(std::vector<double>& output) override;
    bool is_tio_v3() override;
    // 0:0x00 DI2输入类型为NPN,DI1输入类型为NPN
    // 1:0x01 DI2输入类型为NPN,DI1输入类型为PNP
    // 2:0x10 DI2输入类型为PNP,DI1输入类型为NPN
    // 3:0x11 DI2输入类型为PNP,DI1输入类型为PNP
    int tio_setup_di_pin_mode(uint32_t cfg) override;
    // 低8位数据有效，低8位数据中，高4位为DO2配置，低四位为DO1配置，具体含义如下：
    // 0x0 DO输出为类型为NPN输出
    // 0x1 DO输出类型为PNP输出
    // 0x2 DO输出类型为推挽输出
    // 0xF RS485H接口使能，DO禁止
    int tio_setup_do_pin_mode(uint32_t cfg) override;
    //  0:模拟输入功能使能，RS485L禁止
    // 1:RS485L接口使能，模拟输入功能禁止
    int tio_setup_ai_pin_mode(uint32_t cfg) override;
    int tio_setup_ao_pin_mode(uint32_t cfg) override { return -1; }  //不支持此功能，预留仿真强制di的扩展性
    int tio_get_di_pin_mode() override;
    int tio_get_do_pin_mode() override;
    int tio_get_ai_pin_mode() override;
    int tio_get_ao_pin_mode() override { return -1; }  //不支持此功能，预留仿真强制di的扩展性

public:
    static const int MAX_RS485_CHANNEL = 3;
    static const uint8_t MAX_RS485_FRAME_SIZE = 8;
    static const uint8_t MAX_RS485_BUFF = MAX_RS485_FRAME_SIZE * 8;
    static const size_t MAX_TRANS_MSG_LEN = 100;
    struct RS485Setting
    {
        uint32_t rs485_sensor_chn = 0;                     // 力传感器所在的通道 0:no use, 1:use RS485_1, 2:use RS485_2
        uint32_t rs485_mode_cfg[MAX_RS485_CHANNEL] = {0};  // 485通道的模式，0 for RTU, 1 for 透传或数据转发
        RS485RTUConfig rs485_comm_cfg[MAX_RS485_CHANNEL] = {0};
        uint32_t rs485_chn_ena[MAX_RS485_CHANNEL] = {0};  // flag for channel enable or not， 由TIO报文决定
    } stat_rs485cfg_;
    // 接受TIO485数据缓存
    struct RS485Msg
    {
        uint16_t data_len = 0;
        bool is_frame_part_in[MAX_RS485_FRAME_SIZE] = {0};
        uint8_t tio_rs485_buf[MAX_RS485_BUFF] = {0};  // buffer the splitted frame
    } rs485_buffer_[MAX_RS485_CHANNEL];               //收集分包数据包用的缓冲

    std::vector<boost::circular_buffer<char>> rs485_trans_buffer_;

    int set_tio_rs485_chn_mode(int chn_id, RS485Mode mode) override;
    int get_tio_rs485_chn_mode(int chn_id) override;
    int set_tio_rs485_chn_comm(int chn_id, RS485RTUConfig rtu_comm_params) override;
    int get_tio_rs485_chn_comm(int chn_id, RS485RTUConfig& rtuComm) override;
    int tio_set_rs485_chn_func(uint32_t cfg) override;  //0x10a 力矩传感器通道选择  考虑改名;

    /**
     * @brief 收集数据，检查分包完整性，更新了成员变量rs485_buffer_
     * 
     * @return True for success, False for failure
     */
    bool collect_frame(uint8_t chn, uint8_t* data, uint8_t len);

    int procRs485ResponseData(int chn_id, uint8_t* buf, int len);
};

class TioV3Board : public TioBoardItf
{
public:
    TioV3Board()
    {
        sim_flag_ = 0;
        sysio__.tiov3 = this;
        usrio__.tiov3 = this;
    }
    ~TioV3Board() = default;
    const char* name() { return "TIOV3"; }
    int init(const char* cfgfile) override;
    int boot() override;
    TioV3SysIoItf* sysio() { return &sysio__; }
    TioV3UsrIoItf* usrio() { return &usrio__; }
    int set_send_data(int busid) override;
    int get_recv_data(int busid) override;

    int get_sdo_blocking(uint32_t objid, void* data, int s, int retry = 3);

    int set_sdo_blocking(uint32_t objid, uint32_t data, size_t s, uint32_t* readback = nullptr, int retry = 3);

    std::shared_ptr<rtbus::RtCommuItf> bus_;  // tiointf为了便于测试中mock通讯类，基类中没有此声明，所以访问不到，
private:
    TioV3SysIoItf sysio__;
    TioV3UsrIoItf usrio__;
};

namespace rtdev {
class TioV3Factory : public TioBoardFactoryItf
{
public:
    TioV3Factory() {}

    TioBoardItf* create() override;
};

}  // namespace rtdev
